/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package dk.rofl.modes;

import dk.eleit.input.InputManager;
import dk.eleit.input.SaveLoadManager;
import dk.rofl.graphics.GameTileSet;
import dk.rofl.items.*;
import dk.rofl.maps.GameMap;
import dk.rofl.maps.MapGenerator;
import dk.rofl.units.Monster;
import dk.rofl.units.Player;
import java.awt.Color;
import java.awt.FontMetrics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.KeyEvent;
import java.io.IOException;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
import rofl.RoFL;

/**
 *
 * @author menderleit
 */
public final class GameMode extends Mode {

    public static final int pfX = 16;
    public static final int pfY = 16;
    private GameMap map;
    private Player player;
    private int gameLevel;
    private int itemSelected;
    private CombatMode cMode;
    private SaveLoadManager slm;

    // Constructor
    public GameMode() {
        // First level.
        gameLevel = 1;
        GameModeUtils.setGameMode(GameModeUtils.STATE_NONE);

        // Load the player sprite.
        try {
            player = new Player(new GameTileSet("media/gfx/knight.png", 32));
        } catch (IOException ex) {
            Logger.getLogger(GameMode.class.getName()).log(Level.SEVERE, null, ex);
        }

        // Give some startup health-potions.
        HealthPotion hp = new HealthPotion(gameLevel);
        for (int i = 0; i < 4; i++) {
            hp.addPotion();
        }
        player.addItem(hp);
        beginLevel();
    }

    // Constructor for loaded game   
    public GameMode(Object[] data) {
        // Load Level
        gameLevel = (Integer) data[0];
        GameModeUtils.setGameMode(GameModeUtils.STATE_NONE);

        // Load the player sprite.
        try {
            player = new Player(new GameTileSet("media/gfx/knight.png", 32));
        } catch (IOException ex) {
            Logger.getLogger(GameMode.class.getName()).log(Level.SEVERE, null, ex);
        }

        // Load Player
        player.loadPlayer((Object[]) data[1]);

        beginLevel();
    }

    // Setup a new Level.
    public void beginLevel() {
        // Load the assets for this Level.
        GameTileSet mapTileSet = null;
        try {
            mapTileSet = new GameTileSet("media/gfx/tiles01.png", 32);
            Monster.setTileSet(new GameTileSet("media/gfx/monster.png", 32));
        } catch (IOException ex) {
            Logger.getLogger(GameMode.class.getName()).log(Level.SEVERE, null, ex);
        }

        // Create the map.
        map = new GameMap(31, 23, mapTileSet);
        MapGenerator.generate(map);
        map.buildTileMap();
        map.fillVisionMap(false);
        map.buildPOIList();
        map.populate(gameLevel);
        map.setVisible(map.getStartPosition());

        // Position the player.
        player.setPosition(map.getStartPosition());

        GameModeUtils.setGameMode(GameModeUtils.STATE_MAIN);
    }

    // Go to the next Level.
    public void nextLevel() {
        gameLevel++;
        beginLevel();
    }

    // Save Game
    public void saveGame() {
        slm = new SaveLoadManager();
        Object[] data = {gameLevel, player.savePlayer()};
        slm.save(data);
        System.out.println("Game Saved");
    }

    @Override
    public void controls(InputManager im) {

        // Release the keyLock if no keys are pressed.
        if (!im.isKeyPressed() && GameModeUtils.getKeyLock()) {
            GameModeUtils.setKeyLock(false);
        }

        // Check controls based on gameState.
        switch (GameModeUtils.getGameMode()) {
            case GameModeUtils.STATE_MAIN:
                Point oldPos = player.getPosition();

                // Return to TitleMode
                if (im.isKeyDown(KeyEvent.VK_ESCAPE) && !GameModeUtils.getKeyLock()) {
                    GameModeUtils.setKeyLock(true);                    
                    ModeSwitcher.setNewMode(ModeSwitcher.MODE_TITLE);                   
                }


                //  Save game
                if (im.isKeyDown(KeyEvent.VK_F11) && !GameModeUtils.getKeyLock()) {
                    GameModeUtils.setKeyLock(true);
                    saveGame();
                }

                // Use the Exit.
                if (im.isKeyDown(KeyEvent.VK_SPACE) && !GameModeUtils.getKeyLock()) {
                    GameModeUtils.setKeyLock(true);
                    if (player.getPosition().equals(map.getEndPosition())) {
                        nextLevel();
                        return;
                    }
                }

                // Inventory Button
                if (im.isKeyDown(KeyEvent.VK_I) && !GameModeUtils.getKeyLock()) {
                    GameModeUtils.setKeyLock(true);
                    itemSelected = 0;
                    GameModeUtils.setGameMode(GameModeUtils.STATE_EQUIP);
                }

                // Movement
                if (im.isKeyDown(KeyEvent.VK_UP) && !GameModeUtils.getKeyLock()) {
                    GameModeUtils.setKeyLock(true);
                    if (!map.getCollision(player.getXPosition(), player.getYPosition() - 1)) {
                        player.moveUp();
                    }
                }
                if (im.isKeyDown(KeyEvent.VK_DOWN) && !GameModeUtils.getKeyLock()) {
                    GameModeUtils.setKeyLock(true);
                    if (!map.getCollision(player.getXPosition(), player.getYPosition() + 1)) {
                        player.moveDown();
                    }
                }
                if (im.isKeyDown(KeyEvent.VK_LEFT) && !GameModeUtils.getKeyLock()) {
                    GameModeUtils.setKeyLock(true);
                    if (!map.getCollision(player.getXPosition() - 1, player.getYPosition())) {
                        player.moveLeft();
                    }
                }
                if (im.isKeyDown(KeyEvent.VK_RIGHT) && !GameModeUtils.getKeyLock()) {
                    GameModeUtils.setKeyLock(true);
                    if (!map.getCollision(player.getXPosition() + 1, player.getYPosition())) {
                        player.moveRight();
                    }
                }
                if (!oldPos.equals(player.getPosition())) {
                    map.setVisible(player.getPosition());
                }
                break;
            case GameModeUtils.STATE_DEAD:
                if (im.isKeyDown(KeyEvent.VK_SPACE) && !GameModeUtils.getKeyLock()) {
                    GameModeUtils.setKeyLock(true);
                    if (player.isDead()) {
                        ModeSwitcher.setNewMode(ModeSwitcher.MODE_TITLE);
                    } else {
                        GameModeUtils.setGameMode(GameModeUtils.STATE_MAIN);
                    }
                }
                break;
            case GameModeUtils.STATE_EQUIP:
                // Inventory Button
                if (im.isKeyDown(KeyEvent.VK_I) && !GameModeUtils.getKeyLock()) {
                    GameModeUtils.setKeyLock(true);
                    GameModeUtils.setGameMode(GameModeUtils.STATE_MAIN);
                }
                if (im.isKeyDown(KeyEvent.VK_DOWN) && !GameModeUtils.getKeyLock()) {
                    GameModeUtils.setKeyLock(true);
                    if (itemSelected < player.getItems().size() - 1) {
                        itemSelected++;
                    } else {
                        itemSelected = 0;
                    }
                }
                if (im.isKeyDown(KeyEvent.VK_UP) && !GameModeUtils.getKeyLock()) {
                    GameModeUtils.setKeyLock(true);
                    if (itemSelected > 0) {
                        itemSelected--;
                    } else {
                        itemSelected = player.getItems().size() - 1;
                    }
                }
                if (im.isKeyDown(KeyEvent.VK_ENTER) && !GameModeUtils.getKeyLock()) {
                    GameModeUtils.setKeyLock(true);
                    player.equipInventoryItem(itemSelected);
                }
                if (im.isKeyDown(KeyEvent.VK_DELETE) && !GameModeUtils.getKeyLock()) {
                    GameModeUtils.setKeyLock(true);
                    player.deleteItem(itemSelected);
                }
                break;
            case GameModeUtils.STATE_COMBAT:
                cMode.controls(im);
                break;
        }
    }

    @Override
    public void update(long difTime) {
        switch (GameModeUtils.getGameMode()) {
            case GameModeUtils.STATE_MAIN:
                if (map.getMonster(player.getXPosition(), player.getYPosition()) != null) {
                    Monster enemy = map.getMonster(player.getXPosition(), player.getYPosition());
                    if (!enemy.isDead()) {
                        cMode = new CombatMode(map, player, enemy, CombatMode.TURN_PLAYER);
                        GameModeUtils.setGameMode(GameModeUtils.STATE_COMBAT);
                    }
                }
                break;
            case GameModeUtils.STATE_COMBAT:
                cMode.update(difTime);
            case GameModeUtils.STATE_DEAD:
                break;
            case GameModeUtils.STATE_EQUIP:
                if (itemSelected > player.getItems().size() - 1) {
                    itemSelected = player.getItems().size() - 1;
                }
                break;
        }
    }

    @Override
    public void draw(Graphics2D g) {
        FontMetrics fm = g.getFontMetrics();
        String s;
        switch (GameModeUtils.getGameMode()) {
            case GameModeUtils.STATE_MAIN:
                map.draw(g, pfX, pfY);
                g.drawImage(player.getImage(), null, player.getXPosition() * map.getTileSize() + pfX, player.getYPosition() * map.getTileSize() + pfY);
                break;
            case GameModeUtils.STATE_DEAD:
            case GameModeUtils.STATE_COMBAT:
                cMode.draw(g);
                break;
            case GameModeUtils.STATE_EQUIP:
                int equipX = 200;
                int equipY = 100;
                int invX = 700;
                int invY = 100;
                g.setColor(Color.white);
                g.drawString("EQUIPPED", equipX, equipY);
                equipY += fm.getHeight() * 2;
                for (int i = 0; i < player.getArmor().length; i++) {
                    drawEquipmentInfo(g, equipX, equipY, player.getArmor()[i]);
                    equipY += fm.getHeight() * 6;
                }
                drawEquipmentInfo(g, equipX, equipY, player.getWeapon());

                g.setColor(Color.white);
                g.drawString("INVENTORY", invX, invY);
                invY += fm.getHeight();
                ArrayList<GameItem> items = player.getItems();
                invY += fm.getHeight();
                if (items.size() > 0) {
                    for (int i = 0; i < items.size(); i++) {
                        GameItem gi = items.get(i);
                        s = "[" + gi.getItemLevel() + "] " + gi.getName();
                        if (i == itemSelected) {
                            g.setColor(Color.darkGray);
                            g.fillRect(invX, invY - fm.getHeight() + 4, fm.stringWidth(s), fm.getHeight());
                        }
                        if (gi instanceof Armor || gi instanceof Weapon) {
                            Equipment equip = (Equipment) gi;
                            g.setColor(Equipment.getItemQualityColor(equip.getItemQuality()));
                        } else {
                            g.setColor(Color.lightGray);
                            if (gi instanceof HealthPotion) {
                                HealthPotion hp = (HealthPotion) gi;
                                s += " " + hp.getHealingString();
                            }
                        }
                        g.drawString(s, invX, invY);
                        invY += fm.getHeight();
                    }
                } else {
                    g.setColor(Color.lightGray);
                    g.drawString("- No Items -", invX, invY);
                }
                break;
        }
        drawStatus(g);
    }

    private void drawItemInfo(Graphics2D g, int x, int y, GameItem item) {
        FontMetrics fm = g.getFontMetrics();

        g.drawString(item.getName(), x, y);
    }

    private void drawEquipmentInfo(Graphics2D g, int x, int y, Equipment equip) {
        FontMetrics fm = g.getFontMetrics();

        // Piece prefix.
        g.setColor(Color.lightGray);
        if (equip instanceof Armor) {
            Armor a = (Armor) equip;
            switch (a.getSlot()) {
                case Armor.SLOT_CHEST:
                    g.drawString("CHEST: ", x - fm.stringWidth("CHEST: "), y);
                    break;
                case Armor.SLOT_FEET:
                    g.drawString("FEET: ", x - fm.stringWidth("FEET: "), y);
                    break;
                case Armor.SLOT_HANDS:
                    g.drawString("HANDS: ", x - fm.stringWidth("HANDS: "), y);
                    break;
                case Armor.SLOT_HEAD:
                    g.drawString("HEAD: ", x - fm.stringWidth("HEAD: "), y);
                    break;
                case Armor.SLOT_LEGS:
                    g.drawString("LEGS: ", x - fm.stringWidth("LEGS: "), y);
                    break;
            }
        }
        if (equip instanceof Weapon) {
            Weapon w = (Weapon) equip;
            g.drawString("WEAPON: ", x - fm.stringWidth("WEAPON: "), y);
        }

        // Item quality colors.
        g.setColor(Equipment.getItemQualityColor(equip.getItemQuality()));
        g.drawString(equip.getName(), x, y);
        y += fm.getHeight();

        // ArmorRating
        if (equip instanceof Armor) {
            Armor a = (Armor) equip;
            g.setColor(Color.lightGray);
            g.drawString("ArmorRating: ", x, y);
            g.setColor(Color.white);
            g.drawString("" + a.getArmorRating(), x + fm.stringWidth("ArmorRating: "), y);
            y += fm.getHeight();
        }

        // Weapon damage.
        if (equip instanceof Weapon) {
            Weapon w = (Weapon) equip;
            g.setColor(Color.lightGray);
            g.drawString("Damage: ", x, y);
            g.setColor(Color.white);
            g.drawString(w.getMinDamage() + " - " + w.getMaxDamage(), x + fm.stringWidth("Damage: "), y);
            y += fm.getHeight();
        }

        // ItemLevel
        g.setColor(Color.lightGray);
        g.drawString("ItemLevel: ", x, y);
        g.setColor(Color.white);
        g.drawString("" + equip.getItemLevel(), x + fm.stringWidth("ItemLevel: "), y);
        y += fm.getHeight();

        g.setColor(Color.cyan);
        if (equip.getStaminaBonus() > 0) {
            g.drawString("+ " + equip.getStaminaBonus() + " stamina", x, y);
            y += fm.getHeight();
        }
        if (equip.getStrengthBonus() > 0) {
            g.drawString("+ " + equip.getStrengthBonus() + " strength", x, y);
        }
    }

    // Draw various status text.
    private void drawStatus(Graphics2D g) {

        // Draw border.
        g.setColor(Color.white);
        g.drawRect(pfX - 2, pfY - 2, map.getWidth() * map.getTileSize() + 3, map.getHeight() * map.getTileSize() + 3);

        // Setup font metrics for centering text.
        FontMetrics fm = g.getFontMetrics();
        String xpS = "XP: " + player.getXp() + "/" + player.getNextLevelXp();
        int xpSize = fm.stringWidth(xpS);
        String hpS = "Health: " + player.getCurrentHealth() + "/" + player.getMaxHealth();
        int hpSize = fm.stringWidth(hpS);
        String goldS = "Gold: " + player.getGold();
        int goldSize = fm.stringWidth(goldS);

        g.setColor(Color.white);

        // Draw the player status.
        g.drawString("PLAYER - Level: " + player.getLevel(), pfX, pfY - 5);
        g.drawString(xpS, (RoFL.SCREEN_WIDTH / 3) - xpSize / 2, pfY - 5);
        g.drawString(goldS, (RoFL.SCREEN_WIDTH / 3) * 2 - goldSize / 2, pfY - 5);
        g.drawString(hpS, pfX + map.getWidth() * map.getTileSize() - hpSize, pfY - 5);

        // Draw the game status.
        g.drawString("GAME - Level: " + gameLevel, pfX, pfY + map.getHeight() * map.getTileSize() + 13);
    }

    @Override
    public void exit() {
        // Get rid of resources or something... :D
    }
}
